<?php
/** 要被过滤的对象 */
class Person
{
    /** @var string $name */
    public $name;
    /** @var "male"|"famale" $gender */
    public $gender;
    /** @var bool $married */
    public $married;
    public function __construct($name, $gender, $married)
    {
        $this->name=$name;
        $this->gender=$gender;
        $this->married=$married;
    }
}

/** 过滤标准的接口 */
interface Criteria
{
    /**
     * @param Person[] $persons
     * @return Person[]
     */
    public function meetCriteria($persons);
}

class CriteriaMale implements Criteria
{
    public function meetCriteria($persons)
    {
        $list=[];
        foreach ($persons as $person) {
            if(strtolower($person->gender) === "male"){
                $list[] = $person;
            }
        }
        return $list;
    }
}
class CriteriaSingle implements Criteria
{
    public function meetCriteria($persons)
    {
        $list=[];
        foreach ($persons as $person) {
            if($person->married === false){
                $list[] = $person;
            }
        }
        return $list;
    }
}
class AndCriteria implements Criteria
{
    protected $criterias=[];
    public function __construct(...$criterias)
    {
        $this->criterias = $criterias;
    }
    public function meetCriteria($persons)
    {
        foreach($this->criterias as $criteria){
            $persons = $criteria->meetCriteria($persons);
        }
        return $persons;
    }
}
class OrCriteria implements Criteria
{
    protected $criterias=[];
    public function __construct(...$criterias)
    {
        $this->criterias = $criterias;
    }
    public function meetCriteria($persons)
    {
        $criterias=$this->criterias;
        if($criteria=array_shift($criterias)){
            $list=$criteria->meetCriteria($persons);
        }
        else return $persons;

        foreach($criterias as $criteria){
            $result = $criteria->meetCriteria($persons);
            foreach($result as $person){
                if(!in_array($person, $list)) $list[] = $person;
            }
        }
        return $list;
    }
}

header('Content-Type: text/plain');

$persons=[
    new Person("Robert","Male", false),
    new Person("John","Male", true),
    new Person("Laura","Female", true),
    new Person("Diana","Female", false),
    new Person("Mike","Male", false),
    new Person("Bobby","Male", false),
];

$male = new CriteriaMale;
$single = new CriteriaSingle;
$and = new AndCriteria($male,$single);
$or = new OrCriteria($male,$single);

print_r($male->meetCriteria($persons));
print_r($single->meetCriteria($persons));
print_r($and->meetCriteria($persons));
print_r($or->meetCriteria($persons));

